#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

unsigned short port = 11001;
char ipaddr[16] = "127.0.0.1";
int child_count = 1;

int safe_tcp_recv (int sockfd, void *buf, int bufsize)
{
	int cur_len, tmp;

	for (cur_len = 0; cur_len < bufsize; ) {
		tmp = recv (sockfd, buf + cur_len, bufsize, 0);
		if (tmp == -1) {
			if (errno != EINTR)
				break;
		} else if (tmp == 0)
			break;
		else
			cur_len += tmp;
	}
	return cur_len;
}

void *thread_run (void *arg)
{
	int     sockfd , i = 0, tolen, ret;
	struct	sockaddr_in servaddr;
	int succ = 0, fail= 0;	
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	inet_pton(AF_INET, ipaddr, &servaddr.sin_addr);
	tolen = sizeof (servaddr);
socket_again:
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (connect (sockfd, (const struct sockaddr *)&servaddr, tolen) != 0)
	{
		fprintf (stderr, "connect error,%s\n", strerror (errno));
		exit (-1);
	}

	printf ("thread %d run ... ...\n", getpid ());
	for (; i < 10000; i++)
	{
		char send_buf[1000],recv_buf[1000]; 
		int length;
		sprintf (send_buf, "%d %d", getpid (), i);
		length = sizeof (send_buf);

		if (length != send (sockfd, send_buf, length, 0))
		{
			printf ("send error,pid=%d,count=%d\n",  getpid (), i);
			fail++;
			close (sockfd);
			goto socket_again;
		}

		ret = safe_tcp_recv (sockfd, recv_buf, length);
		if (length != ret)
		{
			printf ("recv error,pid=%d,count=%d, length=%d\n",  getpid (), i, ret);
			fail++;
			close (sockfd);
			goto socket_again;
		}

		if (memcmp (recv_buf, send_buf, length) != 0) {
			printf ("strmcp error\n");
			fail++;
		} else {
			succ ++;
		}
	}

	printf ("%d: total=%d, fail=%d, succ=%d \n", getpid(), i, fail, succ);
	return NULL;
}

int main (int argc, char* argv[])
{
	int c, i;
	for (; (c = getopt (argc, argv, "p:c:i:")) != -1;)
	{
		switch (c)
		{
			case 'c':
				child_count = atoi (optarg);
				break;
			case 'p':
				port = atoi (optarg);
				break;
			case 'i':
				strncpy (ipaddr, optarg, sizeof (ipaddr) - 1);
				break; 
		}
	}
	signal (SIGPIPE, SIG_IGN);
	pthread_t *thread_tid = (pthread_t*)calloc (child_count, sizeof (pthread_t));
	for (i = 0; i < child_count; i++)
		pthread_create (&thread_tid[i], NULL, &thread_run, NULL);

	for (i = 0; i < child_count; i++)
		pthread_join (thread_tid[i], NULL);
	return 0;
}
